﻿// This source file is part of the atomdb project
// 
// Copyright (c) 2017 - 2022 pulsarware, All rights reserved.
// Copyright (c) 2017 - 2022 polarboy <polarboy@163.com>
// 
// See https://atomdb.com/LICENSE.txt for license information
// 
// Created by polarboy on 2023/12/02.

using System.Diagnostics;
using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Pulsarware.ATOMDB.Packager;

public record DetectCmdExecResult
{
   public int ExitCode { get; set; }
   public string? StdErrorMsg { get; set; }
   public string? StdOutputMsg { get; set; }
}

public abstract class AbstractHostDetector : IHostDetector
{
   protected readonly ToolChain _toolChain;
   protected readonly Config _config;

   protected AbstractHostDetector(IOptions<Config> config)
   {
      _toolChain = new ToolChain();
      _config = config.Value;
   }
   
   public abstract Task<bool> DetectAsync();

   public ToolChain ToolChainInfo()
   {
      return _toolChain;
   }

   protected async Task<DetectCmdExecResult> ExecCommandAsync(string command, IEnumerable<string> args)
   {
      var startInfo = new ProcessStartInfo(command, args)
      {
         WorkingDirectory = _config.BuildDir is not null ? _config.BuildDir.FullName : String.Empty,
         UseShellExecute = false,
         CreateNoWindow = false,
         RedirectStandardError = true,
         RedirectStandardOutput = true,
         RedirectStandardInput = true
      };
      var result = new DetectCmdExecResult();
      var stdErrorMsg = "";
      var stdOutputMsg = "";
      try
      {
         using var process = new Process()
         {
            StartInfo = startInfo
         };
         
         if (!process.Start())
         {
            result.ExitCode = process.ExitCode;
            result.StdErrorMsg = "Process start failed";
            return result;
         }
         
         do
         {
            await Task.WhenAny(process.WaitForExitAsync(), Task.Delay(10));
            if (process.StandardOutput.BaseStream.CanRead)
            {
               stdOutputMsg = await process.StandardOutput.ReadToEndAsync();
            }
            if (process.StandardError.BaseStream.CanRead)
            {
               stdErrorMsg = await process.StandardError.ReadToEndAsync();
            }
            
         } while (!process.HasExited);
         result.ExitCode = process.ExitCode;
         result.StdErrorMsg = stdErrorMsg;
         result.StdOutputMsg = stdOutputMsg;
      }
      catch (Exception e)
      {
         result.ExitCode = -1;
         result.StdErrorMsg = e.Message;
      }
      return result;
   }
   
   protected abstract string? findCommandPath(string command);
   protected abstract Task<string?> findCommandPathAsync(string command);
}